<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <ul id="ul">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
  </ul>
  <script type="text/javaScript">
    // 工厂模式
    // 不需要关心内部逻辑，只需要传入参数，调用方法就能创建需要的对象。
    class Man {
      constructor (name) {
        this.name = name
      }
      alertName() {
        alert(this.name)
      }
    }

    class Factory {
      static create (name) {
        return new Man(name)
      }
    }

    Factory.create('zrz').alertName()

    // 单例模式
    // 单例模式很常用，比如全局缓存、全局状态管理等等这些只需要一个对象，就可以使用单例模式
    // 说白了就是全局保证只有一个实例对象
    class Singleton {
      constructor () {
      }
    }

    Singleton.getInstance = (function () {
      let getInstance
      return function () {
        // 如果对象不存在就创建，如果存在就直接返回已经存在的对象
        if (!instance) {
          instance = new Singleton()
        }
        return instance
      }
    })()
    // s1 跟 s2 是同一个实例
    let s1 = Singleton.getInstance()
    let s2 = Singleton.getInstance()
    console.log(s1 === s2)

    // 适配器模式
    // computed 就使用了适配器模式
    class Plug {
      getName () {
        return '港版插头'
      }
    }

    class Target {
      constructor () {
        this.plug = new Plug()
      }
      getName () {
        return this.plug.getName() + '适配器转二脚插头'
      }
    }

    let target = new Target()
    let name = target.getName()
    console.log(name)

    // 装饰模式
    // 装饰模式不需要改变已有的接口，作用是给对象添加功能。
    // 就想我们经常需要给手机戴个保护套防摔一样，不改变手机自身，给手机添加了保护套提供防摔功能。
    // es7 中实现装饰模式的例子 (被babel支持)
    function readonly (target, key, descriptor) {
      descriptor.writable = false
      return descriptor
    }

    class Test {
      @readonly
      name = 'yck'
    }
    
    let t = new Test

    t.yck = '111' // 不可修改

    // 代理模式
    // 因为存在太多的li，不可能每个都去绑定事件。
    // 这时候可以通过给父节点绑定一个事件，让父节点为代理去拿到真实点击的节点。
    let ul = document.querySelector('#ul')
    ul.addEventListener('click', (event) => {
      console.log(event.target)
    })
  </script>
</body>
</html>